import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DeleteResult, Repository, UpdateResult } from 'typeorm';
import { Bk_Product } from './bk_product.entity';
import { join } from 'path';
import * as fs from 'fs';
import { Bk_Product_Info } from 'src/product_info/product_info.entity';
import { v1 } from 'node-uuid';

@Injectable()
export class ProductService {
    constructor(
        @InjectRepository(Bk_Product)
        private readonly productRepository: Repository<Bk_Product>,
        @InjectRepository(Bk_Product_Info)
        private readonly productInfoRepository: Repository<Bk_Product_Info>
    ) { }

    async uploadFiles(files: any, products: any, id: number) {//文件上传
        fs.writeFileSync(join(__dirname, '..', 'public', 'image', products.thumbnail_url), files.thumbnail[0].buffer);
        if (products.product_type == 0) {//视频
            if (files.product) {
                for (let i = 0; i < files.product.length; i++) {
                    let product_url = v1() + '.' + (files.product[i].originalname).split('.')[1];
                    fs.writeFileSync(join(__dirname, '..', 'public', 'video', product_url), files.product[i].buffer);
                    await this.productInfoRepository.save({
                        product_name: files.product[i].originalname.split('.')[0],
                        product_url,
                        product: { id }
                    });
                }
            }
        } else {//试卷
            const testPaperName = v1() + '.html';
            fs.writeFileSync(join(__dirname, '..', 'public', 'image', products.thumbnail_url), files.thumbnail[0].buffer);
            fs.writeFileSync(join(__dirname, '..', 'public', 'testPaper', testPaperName), products.testPaper);
            await this.productInfoRepository.save({
                product_name: products.product_name,
                product_url: testPaperName,
                product: { id }
            });
        }
    }
    //单个添加文件
    async uploadFile(filePath: 'image' | 'video' | 'testPaper', fileName: string, buffer: string | NodeJS.ArrayBufferView) {
        fs.writeFileSync(join(__dirname, '..', 'public', filePath, fileName), buffer);
    }
    // 新增视频
    async appendVideoFiles(productId: number, files: any[]) {
        for (let i = 0; i < files.length; i++) {
            let product_url = v1() + '.' + (files[i].originalname).split('.')[1];
            this.uploadFile('video', product_url, files[i].buffer)
            await this.addProductInfo(files[i].originalname.split('.')[0], product_url, productId);
        }
    }
    // 新增试卷
    async appendTestPaper(productName: string, testPaper: string, productId: number) {
        const testPaperName = v1() + '.html';
        this.uploadFile('testPaper', testPaperName, testPaper);
        await this.addProductInfo(productName, testPaperName, productId)
    }
    // 添加一个商品信息
    async addProductInfo(product_name: string, product_url: string, productId: number) {
        return await this.productInfoRepository.save({
            product_name,
            product_url,
            product: { id: productId }
        });
    }
    removeFiles(product_info: any, thumbnail_url: string, product_type: number) {//删除文件
        let folder = product_type == 0 ? 'video' : 'testPaper';
        product_info.forEach((item: { product_url: string; }) => {
            fs.unlink(join(__dirname, '..', 'public', folder, item.product_url), () => console.log(`删除 ${item.product_url} 成功！`));
        })
        fs.unlink(join(__dirname, '..', 'public', 'image', thumbnail_url), () => console.log(`删除 ${thumbnail_url} 成功！`));
    }
    // 单个删除文件
    removeFile(filePath: 'image' | 'video' | 'testPaper', fileName: string) {
        fs.unlink(join(__dirname, '..', 'public', filePath, fileName), () => console.log(`删除 ${fileName} 成功！`));
    }

    async add(files: any, body: any): Promise<Bk_Product> {//添加商品
        const {
            product_name,
            product_description,
            product_price,
            product_type,
            subject,
            series,
            testPaper,
            original_testPaper,
            videos
        } = body;
        const thumbnail_url = v1() + '.' + files.thumbnail[0].originalname.split('.')[1];
        const product = {
            thumbnail_url,
            product_name,
            product_description,
            product_price,
            product_type,
            subject,
            series,
            original_testPaper
        }
        const { id } = await this.productRepository.save(product);
        if (product_type == 0) {
            const productInfo = JSON.parse(videos[0]);
            let productInfoList = [];
            for (const key in productInfo) {
                productInfoList.push(productInfo[key]);
            }
            for (let i = 0; i < productInfoList.length; i++) {
                await this.addProductInfo(productInfoList[i].file_name, productInfoList[i].file_path, id)
            }
        } else {
            await this.appendTestPaper(product_name, testPaper, id);
        }
        this.uploadFile('image', thumbnail_url, files.thumbnail[0].buffer);
        return await this.productRepository.findOne({ relations: ["subject", "series", "product_info"], where: { id } });
    }

    async delete(id: number): Promise<DeleteResult> {//删除商品
        const { thumbnail_url, product_info, product_type } = await this.productRepository.findOne({ relations: ["product_info"], where: { id } });
        for (let i = 0; i < product_info.length; i++) {
            await this.productInfoRepository.delete({ product: { id } });
        }
        this.removeFiles(product_info, thumbnail_url, product_type);
        return await this.productRepository.delete(id);
    }

    async update(files: any, product: any): Promise<UpdateResult> {//更新商品

        if (!product?.id) {
            throw new HttpException({
                status: HttpStatus.FORBIDDEN,
                error: '缺少参数id'
            }, HttpStatus.FORBIDDEN);
        }
        const productFindReslut = await this.productRepository.findOne({ relations: ["subject", "series", "product_info"], where: { id: product.id } });
        if (!productFindReslut) {
            throw new HttpException({
                status: HttpStatus.FORBIDDEN,
                error: '要修改的商品不存在！',
            }, HttpStatus.FORBIDDEN)
        }
        const { product_info, thumbnail_url, product_type, id, product_name } = productFindReslut;

        // 如果收到图片则更新图片
        if (files && files.thumbnail) {
            this.removeFile('image', thumbnail_url);
            this.uploadFile('image', thumbnail_url, files.thumbnail[0].buffer);
        }
        if (product_type === 0) {
            // 新增视频
            if (files && files.product) {
                this.appendVideoFiles(id, files.product);
            }
            // 删除视频
            if (product && product.drop_product) {
                const dropProduct = typeof product.drop_product === 'string' ? [product.drop_product] : product.drop_product;
                for (let i = 0; i < dropProduct.length; i++) {
                    const filePath = dropProduct[i];
                    const productInfo = product_info.find(info => info.product_url === filePath);
                    if (productInfo) {
                        this.removeFile('video', filePath);
                        await this.productInfoRepository.delete({ id: productInfo.id });
                    }
                }
            }
        } else if (product.original_testPaper && product_type === 1) { // 修改试卷,试卷只有一个，试卷只能修改
            // 先把原来的删掉
            this.removeFile('testPaper', product_info[0].product_url);
            await this.productInfoRepository.delete({ id: product_info[0].id });
            this.appendTestPaper(product.product_name || product_name, product.original_testPaper, id);
        }
        // 更新其它参数,剔除不能更新的参数
        const updateProduct = {};
        for (const key in product) {
            if (Object.prototype.hasOwnProperty.call(productFindReslut, key) && key !== 'thumbnail_url' && key !== 'product_info' && key !== 'original_testPaper' && key !== 'product_type' && key !== 'id') {
                updateProduct[key] = product[key];
            }
        }
        // 没有则不更新
        if (Object.keys(updateProduct).length > 0) {
            await this.productRepository.update(id, updateProduct);
        }
        return;
    }

    async findAll(query: any): Promise<[Bk_Product[], number]> {
        const where: {
            subject?: { id: number }
            series?: { id: number }
            product_type?: number
        } = {};
        query.subjectId && (where.subject = { id: query.subjectId });
        query.seriesId && (where.series = { id: query.seriesId });
        query.product_type && (where.product_type = query.product_type);

        return await this.productRepository.findAndCount({
            relations: ["subject", "series", "product_info"],
            order: { id: "ASC" },
            skip: query.skip,
            take: query.take,
            where
        })
    }

    async getProductsByCategory(subjectId: number, seriesId: number): Promise<Bk_Product[]> {//分类查询
        // return await this.productRepository.find({
        //     relations: ["subject", "series", "product_info"],
        //     where: {
        //         subject: { id: query.subjectId },
        //         series: { id: query.seriesId }
        //     }
        // });
        let sql = 'select * from bk_product where ';
        if (subjectId && seriesId) {
            sql += `subjectId = ${subjectId} and seriesId = ${seriesId}`;
        } else if (subjectId) {
            sql += `subjectId = ${subjectId}`;
        } else {
            sql += `seriesId = ${seriesId}`;
        }
        return await this.productRepository.query(sql);
    }

    async getProductById(id: number): Promise<Bk_Product> {//按id查询
        return await this.productRepository.findOne({ relations: ["subject", "series", "product_info"], where: { id } });
    }

    async getProductsByType(product_type: number): Promise<Bk_Product[]> {//按类型查询
        return await this.productRepository.find({ relations: ["subject", "series", "product_info"], where: { product_type } });
    }
}